import _ from "lodash";
import scale from "@/assets/images/scale.png";
import Taro from "@tarojs/taro";
import tool from "@/utils/tool";
import { ComponentClass } from "react";
import { Image, View } from "@tarojs/components";
import "./index.sass";

type ComponentStateProps = {};
type ComponentOwnProps = {
  onChangeStyle: () => void;
  onTouchStart: (data?: any) => void;
  onTouchEnd: (data?: any) => void;
  onImageLoaded?: (detail: object, item?: any) => void;
  url: string;
  stylePrams: any;
};
type ComponentState = {
  framePrams: {
    width: number;
    height: number;
    left: number;
    top: number;
  };
};

type IProps = ComponentStateProps & ComponentOwnProps;

interface Sticker {
  props: IProps;
  debouncedStickerOnTouchMove: () => void;
  debouncedArrowOnTouchMove: () => void;
}

class Sticker extends Taro.Component {
  static defaultProps = {
    id: "",
    zIndex: 0,
    width: 0,
    height: 0,
    x: 0,
    y: 0,
    rotate: 0,
    originWidth: 0,
    originHeight: 0,
    autoWidth: 0,
    autoHeight: 0,
    autoScale: 1,
    fixed: false,
    isActive: false,
    visible: true
  };

  state = {
    framePrams: {
      width: 0,
      height: 0,
      left: 0,
      top: 0
    }
  };

  private gesture: {
    preV: { x: number | null; y: number | null };
    center: { x: number; y: number };
    [props: string]: any;
  } = {
    startX: 0,
    startY: 0,
    zoom: false,
    distance: 0,
    preV: { x: null, y: null },
    center: { x: 0, y: 0 },
    scale: 1
  };

  get isFixed(): boolean {
    const { stylePrams } = this.props;
    return stylePrams.fixed || false;
  }

  constructor(props) {
    super(props);
    // this.throttledStickerOnTouchmove = this.throttle
    this.debouncedArrowOnTouchMove = _.debounce(
      this.stickerOnTouchMove,
      1000 / 20
    ).bind(this);
    this.debouncedStickerOnTouchMove = _.debounce(
      this.arrowOnTouchMove,
      1000 / 20
    ).bind(this);
  }

  componentWillMount() {}

  componentWillReceiveProps(nextProps) {
    // 当传入的framePrams大于0的时候更新视图
    if (nextProps.framePrams && nextProps.framePrams > 0) {
      this.setState({
        framePrams: nextProps.framePrams
      });
    }
  }

  arrowOnTouchStart(e) {
    if (this.isFixed) return; // 固定的时候不可以移动
    const { gesture } = this;
    const { stylePrams } = this.props;
    const { framePrams } = this.state;
    const { left: frameOffsetX, top: frameOffsetY } = framePrams;
    const center = tool.getCenterPosition(
      stylePrams.x,
      stylePrams.y,
      stylePrams.width,
      stylePrams.height
    );
    // 如果点击点数量为1
    if (e.touches.length === 1) {
      let { clientX, clientY } = e.touches[0];
      gesture.startX = clientX - frameOffsetX;
      gesture.startY = clientY = frameOffsetY;
      let xMove = clientX - frameOffsetX - center.x;
      let yMove = clientY - frameOffsetY - center.y;
      let distance = Math.sqrt(xMove * xMove + yMove * yMove);
      // 记录旋转
      let v = { x: xMove, y: yMove };
      gesture.distance = distance;
      gesture.zoom = true;
      gesture.preV = v;
      gesture.center = center;
    }
    this.emitTouchStart();
  }
  arrowOnTouchMove(e) {
    if (this.isFixed) return;
    const { gesture } = this;
    const { stylePrams } = this.props;
    const { center } = gesture;
    const { framePrams } = this.state;
    const { left: frameOffsetX, top: frameOffsetY } = framePrams;

    if (e.touches.length === 1) {
      let xMove = e.touches[0].clientX - frameOffsetX - center.x;
      let yMove = e.touches[0].clientY - frameOffsetY - center.y;
      let distance = Math.sqrt(xMove * xMove + yMove * yMove);
      let distanceDiff = distance - gesture.distance;
      let newScale = gesture.scale + 0.005 * distanceDiff;
      if (newScale < 0.2) newScale = 0.2;
      if (newScale > 4) newScale = 4;
      let newWidth = newScale * stylePrams.autoWidth;
      let newHeight = newScale * stylePrams.autoHeight;
      let newX =
        stylePrams.x - (newWidth - gesture.scale * stylePrams.autoWidth) * 0.5;
      let newY =
        stylePrams.y -
        (newHeight - gesture.scale * stylePrams.autoHeight) * 0.5;
      // 计算旋转
      let newRotate: number | null = null;
      let preV = gesture.preV;
      let v = {
        x: xMove,
        y: yMove
      };
      if (!_.isNull(preV.x)) {
        let angle = tool.getRotateAngle(v, preV as any);
        newRotate = _.toNumber(stylePrams.rotate) + angle; // 取整
      }
      // 更新数据
      gesture.scale = newScale;
      gesture.distance = distance;
      gesture.preV = v;
      stylePrams.width = newWidth;
      stylePrams.height = newHeight;
      stylePrams.x = newX;
      stylePrams.y = newY;
      stylePrams.rotate = newRotate;
      // 修改样式
      this.changeStyleParams({
        ...stylePrams,
        width: newWidth,
        height: newHeight,
        x: newX,
        y: newY,
        rotate: newRotate
      });
    }
  }
  arrowOnTouchEnd(e) {
    //  如果固定则不能动
    if (this.isFixed) return;
    if (e.touches.length) {
      this.gesture.zoom = false;
    }
    this.emitTouchEnd();
  }

  changeStyleParams(obj: any, type?: string) {
    const { stylePrams, onChangeStyle } = this.props;
    let newStylePrams: any = null;
    if (type === "offset") {
      const { offsetX, offsetY } = obj;
      newStylePrams = {
        ...stylePrams,
        x: stylePrams.x + offsetX,
        y: stylePrams.y + offsetY
      };
    } else {
      newStylePrams = {
        ...stylePrams,
        ...obj
      };
    }
    // 触发样式改变钩子
    _.isFunction(onChangeStyle) && onChangeStyle(newStylePrams);
  }

  // 触摸开始与结束事件监听
  emitTouchStart() {
    const { onTouchStart, stylePrams } = this.props;
    typeof onTouchStart === "function" && onTouchStart(stylePrams);
  }
  emitTouchEnd() {
    const { onTouchEnd, stylePrams } = this.props;
    typeof onTouchEnd === "function" && onTouchEnd(stylePrams);
  }

  formatStyle(style: any) {
    const { zIndex, width, height, x, y, rotate } = style;
    return {
      zIndex,
      width: `${width} px`,
      height: `${height} px`,
      transform: `translate(${x}, ${y}, rotate(${rotate} deg))`
    };
  }

  stickerOnTouchStart(e) {
    // 固定不可以移动
    if (this.isFixed) return;

    const { gesture } = this;
    const { framePrams } = this.state;
    const frameOffsetX = framePrams.left;
    const frameOffsetY = framePrams.top;
    if (e.touches.length === 1) {
      let { clientX, clientY } = e.touches[0];
      gesture.startX = clientX - frameOffsetX;
      gesture.startY = clientY - frameOffsetY;
    } else {
      let xMove: number = e.touches[1].clientX - e.touches[0].clientX;
      let yMove: number = e.touches[1].clientY - e.touches[0].clientY;
      // 勾股定理求距离
      let distance = Math.sqrt(xMove * xMove + yMove * yMove);
      let v = { x: xMove, y: yMove };
      gesture.preV = v;
      gesture.distance = distance;
      gesture.zoom = true;
      console.debug("双指缩放", gesture);
    }
    this.emitTouchStart();
  }

  stickerOnTouchMove(e) {
    // 固定不可以移动
    if (this.isFixed) return;

    const { gesture } = this;
    const { stylePrams } = this.props;
    const { framePrams } = this.state;
    const { left: frameOffsetX, top: frameOffsetY } = framePrams;

    // 单指移动
    if (e.touches.length === 1) {
      // 缩放状态，不做处理
      if (gesture.zoom) return;

      let { clientX, clientY } = e.touches[0];
      const pointX = clientX - frameOffsetX; // 触摸点所在的画框坐标系X坐标
      const pointY = clientY - frameOffsetY; // 触摸点所在的画框坐标系Y坐标
      let offsetX = pointX - gesture.startX;
      let offsetY = pointY - gesture.startY;
      gesture.startX = pointX;
      gesture.startY = pointY;
      this.changeStyleParams(
        {
          offsetX,
          offsetY
        },
        "offset"
      );
      // 双指缩放
    } else {
      let xMove = e.touches[1].clientX - e.touches[0].clientX;
      let yMove = e.touches[1].clientY - e.touches[0].clientY;
      let distance = Math.sqrt(xMove * xMove + yMove * yMove);

      // 计算缩放
      let distanceDiff = distance - gesture.distance;
      let newScale = gesture.scale + 0.005 * distanceDiff;
      // 设置上限与下限
      if (newScale < 0.3) newScale = 0.3;
      else if (newScale > 4) newScale = 4;

      let newWidth = newScale * stylePrams.autoWidth;
      let newHeight = newScale * stylePrams.autoHeight;
      let newX =
        stylePrams.x - (newWidth - gesture.scale * stylePrams.autoWidth) * 0.5;
      let newY =
        stylePrams.y -
        (newHeight - gesture.scale * stylePrams.autoHeight) * 0.5;
      // 计算旋转
      let newRotate = 0;
      let preV = gesture.preV;
      let v = {
        x: xMove,
        y: yMove
      };
      if (!_.isNull(preV.x)) {
        let angle = tool.getRotateAngle(v, preV as any);
        newRotate = _.toNumber(stylePrams.rotate) + angle;
      }
      // 更新数据
      gesture.scale = newScale;
      gesture.distance = distance;
      gesture.preV = v;
      this.changeStyleParams({
        ...stylePrams,
        width: newWidth,
        height: newHeight,
        x: newX,
        y: newY,
        rotate: newRotate
      });
    }
  }

  stickerOnTouchEnd(e) {
    if (this.isFixed) return; // 如果固定则不可以移动
    // 如果接触点数量为0，则不进行缩放
    if (e.touches.length === 0) this.gesture.zoom = false;
    this.emitTouchEnd();
  }

  // 处理图片加载完成
  handleImageLoaded() {
    const { onImageLoaded, stylePrams } = this.props;
    _.isFunction(onImageLoaded) && onImageLoaded(stylePrams);
  }

  render() {
    const { url, stylePrams } = this.props;
    // const { framePrams } = this.state;
    const styleObj = this.formatStyle(this.props.stylePrams);
    return (
      <View
        className={`sticker-wrap ${stylePrams.fixed ? "event-through" : ""} ${
          stylePrams.visible && _.gt(stylePrams.width, 0) ? "" : "hidden"
        }`}
        style={styleObj}
      >
        {/* <View style="position: absolute;left:0;top:0">{framePrams.width}</View> */}
        {/* <View style="position: absolute;left:0;top:20px">{stylePrams.autoWidth}</View> */}
        {/* <View style="position: absolute;left:0;top:20px">{stylePrams.width}</View>  */}
        <Image
          src={url}
          mode="widthFix"
          style="width: 100%; height: 100%;"
          onLoad={() => this.handleImageLoaded()}
          onTouchStart={(e) => this.stickerOnTouchStart(e)}
          onTouchMove={() => this.debouncedStickerOnTouchMove()}
          onTouchEnd={(e) => this.stickerOnTouchEnd(e)}
        />
        <View className={`border ${stylePrams.isActive ? "active" : ""}`} />
        <View
          className={`control ${stylePrams.isActive ? "acitive" : ""}`}
          onTouchStart={(e) => this.arrowOnTouchStart(e)}
          onTouchMove={() => this.debouncedArrowOnTouchMove()}
          onTouchEnd={(e) => this.arrowOnTouchEnd(e)}
        >
          <Image src={scale} mode="widthFix" style="width: 50%; height: 50%;" />
        </View>
      </View>
    );
  }
}

export default Sticker as ComponentClass<ComponentOwnProps, ComponentState>;
